package com.jin.jpa.wrapper.expression;

import com.jin.jpa.wrapper.LambdaWrapperContext;
import com.jin.jpa.wrapper.WrapperHandler;
import com.jin.jpa.wrapper.support.FieldFunction;
import com.jin.jpa.wrapper.support.IWrapper;
import com.jin.jpa.wrapper.util.LambdaUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: yuanxiuyao
 * @Date: 2024/1/8 16:31
 * @PackageName: org.example.jpa.wrapper.expression
 * @Version 1.0
 */
public class WhereOpExpression<T> extends WrapperHandler<T> implements IExpression<Predicate>{

    private List<IExpression<Predicate>> expressionList = new ArrayList<>();

    private ExpressionOp whereOp;

    public WhereOpExpression(ExpressionOp whereOp, IWrapper<T> iWrapper){
        super(iWrapper);
        this.whereOp = whereOp;
    }

    public Predicate toHandle(LambdaWrapperContext<?> context) {
        List<Predicate> predicates = expressionList.stream().map(where -> where.toHandle(context)).collect(Collectors.toList());
        return toPredicate(context, predicates);
    }

    public Predicate toPredicate(LambdaWrapperContext<?> context, List<Predicate> predicates) {
        CriteriaBuilder criteriaBuilder = context.getCriteriaBuilder();
        switch (whereOp) {
            case AND:
                return criteriaBuilder.and(predicates.toArray(Predicate[]::new));
            case OR:
                return criteriaBuilder.or(predicates.toArray(Predicate[]::new));
        }
        return null;
    }

    public WhereOpExpression<T> equal(FieldFunction<T, ?> expression, Object value){
        PropertyDescriptor propertyDescriptor = LambdaUtils.extract(expression, iWrapper.getInstanceClass());
        WhereExpression whereExpression = WhereExpression.of(propertyDescriptor.getName(), value, WhereExpression.WhereOp.EQ);
        expressionList.add(whereExpression);
        return this;
    }

    public WhereOpExpression<T> isNull(FieldFunction<T, ?> expression){
        PropertyDescriptor propertyDescriptor = LambdaUtils.extract(expression, iWrapper.getInstanceClass());
        WhereExpression whereExpression = WhereExpression.of(propertyDescriptor.getName(), null, WhereExpression.WhereOp.IS_NULL);
        expressionList.add(whereExpression);
        return this;
    }

    public WhereOpExpression<T> isNotNull(FieldFunction<T, ?> expression){
        PropertyDescriptor propertyDescriptor = LambdaUtils.extract(expression, iWrapper.getInstanceClass());
        WhereExpression whereExpression = WhereExpression.of(propertyDescriptor.getName(), null, WhereExpression.WhereOp.IS_NOT_NULL);
        expressionList.add(whereExpression);
        return this;
    }

    public WhereOpExpression<T> between(FieldFunction<T, ?> expression, Object value1, Object value2){
        PropertyDescriptor propertyDescriptor = LambdaUtils.extract(expression, iWrapper.getInstanceClass());
        ScopeExpression scopeExpression = ScopeExpression.of(propertyDescriptor.getName(), ScopeExpression.ScopeOp.BETWEEN, value1, value2);
        expressionList.add(scopeExpression);
        return this;
    }

    public enum ExpressionOp{
        AND,
        OR
    }
}
